package com.deepwiki.controller;

import com.deepwiki.dto.DirectoryTreeNode;
import com.deepwiki.service.DirectoryTreeService;
import com.deepwiki.storage.impl.ElasticsearchStorageStrategy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Wiki API控制器 - 修正版
 * 支持新的ES索引结构，提供文档和目录树访问API
 */
@RestController
@RequestMapping("/api/wiki")
@CrossOrigin(origins = "*")
public class WikiController {

    private static final Logger logger = LoggerFactory.getLogger(WikiController.class);

    private final DirectoryTreeService directoryTreeService;
    private final ElasticsearchStorageStrategy elasticsearchStorage;

    @Autowired
    public WikiController(DirectoryTreeService directoryTreeService, ElasticsearchStorageStrategy elasticsearchStorage) {
        this.directoryTreeService = directoryTreeService;
        this.elasticsearchStorage = elasticsearchStorage;
    }

    /**
     * 获取仓库的目录树
     *
     * @param warehouseId 仓库ID
     * @return 目录树
     */
    @GetMapping("/{warehouseId}/directory-tree")
    public ResponseEntity<Map<String, Object>> getDirectoryTree(@PathVariable String warehouseId) {
        try {
            logger.info("获取目录树: {}", warehouseId);
            
            List<DirectoryTreeNode> directoryTree = directoryTreeService.getDirectoryTree(warehouseId);
            
            Map<String, Object> response = new HashMap<>();
            response.put("success", true);
            response.put("data", directoryTree);
            response.put("warehouseId", warehouseId);
            response.put("timestamp", System.currentTimeMillis());
            
            return ResponseEntity.ok(response);
            
        } catch (Exception e) {
            logger.error("获取目录树失败: {}", warehouseId, e);
            
            Map<String, Object> response = new HashMap<>();
            response.put("success", false);
            response.put("message", "获取目录树失败: " + e.getMessage());
            response.put("warehouseId", warehouseId);
            response.put("timestamp", System.currentTimeMillis());
            
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
        }
    }

    /**
     * 获取文档内容
     *
     * @param warehouseId 仓库ID
     * @param contentPath 内容路径
     * @return 文档内容
     */
    @GetMapping("/{warehouseId}/content")
    public ResponseEntity<Map<String, Object>> getContent(
            @PathVariable String warehouseId,
            @RequestParam String contentPath) {
        try {
            logger.info("获取文档内容: {}, 路径: {}", warehouseId, contentPath);
            
            // 验证路径安全性
            if (!isValidContentPath(contentPath)) {
                Map<String, Object> response = new HashMap<>();
                response.put("success", false);
                response.put("message", "无效的内容路径");
                response.put("timestamp", System.currentTimeMillis());
                return ResponseEntity.badRequest().body(response);
            }
            
            // 从路径解析documentId (去掉.md后缀)
            String documentId = contentPath.replace(".md", "").replace("/", "_");
            
            // 使用兼容方法获取内容，优先使用新的结构化方法
            String content = elasticsearchStorage.readMarkdown(warehouseId, documentId);
            
            if (content == null) {
                Map<String, Object> response = new HashMap<>();
                response.put("success", false);
                response.put("message", "内容不存在");
                response.put("documentId", documentId);
                response.put("timestamp", System.currentTimeMillis());
                return ResponseEntity.notFound().build();
            }
            
            Map<String, Object> response = new HashMap<>();
            response.put("success", true);
            response.put("content", content);
            response.put("contentPath", contentPath);
            response.put("documentId", documentId);
            response.put("warehouseId", warehouseId);
            response.put("timestamp", System.currentTimeMillis());
            
            return ResponseEntity.ok(response);
            
        } catch (Exception e) {
            logger.error("获取文档内容失败: {}, 路径: {}", warehouseId, contentPath, e);
            
            Map<String, Object> response = new HashMap<>();
            response.put("success", false);
            response.put("message", "获取文档内容失败: " + e.getMessage());
            response.put("timestamp", System.currentTimeMillis());
            
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
        }
    }

    /**
     * 检查内容是否存在
     *
     * @param warehouseId 仓库ID
     * @param contentPath 内容路径
     * @return 是否存在
     */
    @GetMapping("/{warehouseId}/content/exists")
    public ResponseEntity<Map<String, Object>> checkContentExists(
            @PathVariable String warehouseId,
            @RequestParam String contentPath) {
        try {
            // 从路径解析documentId (去掉.md后缀)
            String documentId = contentPath.replace(".md", "").replace("/", "_");
            boolean exists = elasticsearchStorage.exists(warehouseId, documentId);
            
            Map<String, Object> response = new HashMap<>();
            response.put("success", true);
            response.put("exists", exists);
            response.put("contentPath", contentPath);
            response.put("documentId", documentId);
            response.put("warehouseId", warehouseId);
            response.put("timestamp", System.currentTimeMillis());
            
            return ResponseEntity.ok(response);
            
        } catch (Exception e) {
            logger.error("检查内容存在性失败: {}, 路径: {}", warehouseId, contentPath, e);
            
            Map<String, Object> response = new HashMap<>();
            response.put("success", false);
            response.put("message", "检查内容存在性失败: " + e.getMessage());
            response.put("timestamp", System.currentTimeMillis());
            
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
        }
    }

    /**
     * 获取目录树统计信息
     *
     * @param warehouseId 仓库ID
     * @return 统计信息
     */
    @GetMapping("/{warehouseId}/stats")
    public ResponseEntity<Map<String, Object>> getStats(@PathVariable String warehouseId) {
        try {
            Map<String, Object> stats = directoryTreeService.getDirectoryTreeStats(warehouseId);
            
            Map<String, Object> response = new HashMap<>();
            response.put("success", true);
            response.put("stats", stats);
            response.put("warehouseId", warehouseId);
            response.put("timestamp", System.currentTimeMillis());
            
            return ResponseEntity.ok(response);
            
        } catch (Exception e) {
            logger.error("获取统计信息失败: {}", warehouseId, e);
            
            Map<String, Object> response = new HashMap<>();
            response.put("success", false);
            response.put("message", "获取统计信息失败: " + e.getMessage());
            response.put("timestamp", System.currentTimeMillis());
            
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
        }
    }

    /**
     * 刷新目录树
     *
     * @param warehouseId 仓库ID
     * @return 操作结果
     */
    @PostMapping("/{warehouseId}/directory-tree/refresh")
    public ResponseEntity<Map<String, Object>> refreshDirectoryTree(@PathVariable String warehouseId) {
        try {
            logger.info("刷新目录树: {}", warehouseId);
            
            directoryTreeService.updateDirectoryTree(warehouseId);
            
            Map<String, Object> response = new HashMap<>();
            response.put("success", true);
            response.put("message", "目录树刷新成功");
            response.put("warehouseId", warehouseId);
            response.put("timestamp", System.currentTimeMillis());
            
            return ResponseEntity.ok(response);
            
        } catch (Exception e) {
            logger.error("刷新目录树失败: {}", warehouseId, e);
            
            Map<String, Object> response = new HashMap<>();
            response.put("success", false);
            response.put("message", "刷新目录树失败: " + e.getMessage());
            response.put("timestamp", System.currentTimeMillis());
            
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
        }
    }

    /**
     * 获取存储信息
     *
     * @return 存储信息
     */
    @GetMapping("/storage/info")
    public ResponseEntity<Map<String, Object>> getStorageInfo() {
        try {
            Map<String, Object> response = new HashMap<>();
            response.put("success", true);
            response.put("storageType", "elasticsearch");
            response.put("version", "2.0.0");
            response.put("indexStructure", "optimized");
            response.put("mappedTables", new String[]{"DocumentFileItems", "DocumentCatalogs", "Documents", "Warehouses", "DocumentOverviews", "DocumentCommitRecords"});
            response.put("timestamp", System.currentTimeMillis());
            
            return ResponseEntity.ok(response);
            
        } catch (Exception e) {
            logger.error("获取存储信息失败", e);
            
            Map<String, Object> response = new HashMap<>();
            response.put("success", false);
            response.put("message", "获取存储信息失败: " + e.getMessage());
            response.put("timestamp", System.currentTimeMillis());
            
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
        }
    }

    /**
     * 获取文档详细信息（新增API，提供更丰富的文档元数据）
     *
     * @param warehouseId 仓库ID
     * @param documentId 文档ID
     * @return 文档详细信息
     */
    @GetMapping("/{warehouseId}/document/{documentId}")
    public ResponseEntity<Map<String, Object>> getDocumentInfo(
            @PathVariable String warehouseId,
            @PathVariable String documentId) {
        try {
            logger.info("获取文档详细信息: {}/{}", warehouseId, documentId);
            
            ElasticsearchStorageStrategy.DocumentInfo documentInfo = 
                    elasticsearchStorage.getDocumentInfo(warehouseId, documentId);
            
            if (documentInfo == null) {
                Map<String, Object> response = new HashMap<>();
                response.put("success", false);
                response.put("message", "文档不存在");
                response.put("warehouseId", warehouseId);
                response.put("documentId", documentId);
                response.put("timestamp", System.currentTimeMillis());
                return ResponseEntity.notFound().build();
            }
            
            Map<String, Object> response = new HashMap<>();
            response.put("success", true);
            response.put("document", convertDocumentInfoToMap(documentInfo));
            response.put("warehouseId", warehouseId);
            response.put("documentId", documentId);
            response.put("timestamp", System.currentTimeMillis());
            
            return ResponseEntity.ok(response);
            
        } catch (Exception e) {
            logger.error("获取文档详细信息失败: {}/{}", warehouseId, documentId, e);
            
            Map<String, Object> response = new HashMap<>();
            response.put("success", false);
            response.put("message", "获取文档详细信息失败: " + e.getMessage());
            response.put("timestamp", System.currentTimeMillis());
            
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
        }
    }

    /**
     * 获取目录信息（新增API，提供目录层级结构信息）
     *
     * @param warehouseId 仓库ID
     * @param catalogId 目录ID
     * @return 目录信息
     */
    @GetMapping("/{warehouseId}/catalog/{catalogId}")
    public ResponseEntity<Map<String, Object>> getCatalogInfo(
            @PathVariable String warehouseId,
            @PathVariable String catalogId) {
        try {
            logger.info("获取目录信息: {}/{}", warehouseId, catalogId);
            
            ElasticsearchStorageStrategy.CatalogInfo catalogInfo = 
                    elasticsearchStorage.getCatalogInfo(warehouseId, catalogId);
            
            if (catalogInfo == null) {
                Map<String, Object> response = new HashMap<>();
                response.put("success", false);
                response.put("message", "目录不存在");
                response.put("warehouseId", warehouseId);
                response.put("catalogId", catalogId);
                response.put("timestamp", System.currentTimeMillis());
                return ResponseEntity.notFound().build();
            }
            
            Map<String, Object> response = new HashMap<>();
            response.put("success", true);
            response.put("catalog", convertCatalogInfoToMap(catalogInfo));
            response.put("warehouseId", warehouseId);
            response.put("catalogId", catalogId);
            response.put("timestamp", System.currentTimeMillis());
            
            return ResponseEntity.ok(response);
            
        } catch (Exception e) {
            logger.error("获取目录信息失败: {}/{}", warehouseId, catalogId, e);
            
            Map<String, Object> response = new HashMap<>();
            response.put("success", false);
            response.put("message", "获取目录信息失败: " + e.getMessage());
            response.put("timestamp", System.currentTimeMillis());
            
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
        }
    }

    /**
     * 验证内容路径是否安全
     */
    private boolean isValidContentPath(String contentPath) {
        if (contentPath == null || contentPath.trim().isEmpty()) {
            return false;
        }
        
        // 防止路径遍历攻击
        if (contentPath.contains("..") || contentPath.contains("//") || contentPath.startsWith("/")) {
            return false;
        }
        
        // 只允许字母、数字、横线、下划线、斜杠和点
        if (!contentPath.matches("^[a-zA-Z0-9\\-_/.]+$")) {
            return false;
        }
        
        return true;
    }

    /**
     * 转换DocumentInfo为Map
     */
    private Map<String, Object> convertDocumentInfoToMap(ElasticsearchStorageStrategy.DocumentInfo documentInfo) {
        Map<String, Object> map = new HashMap<>();
        map.put("documentId", documentInfo.documentId);
        map.put("catalogId", documentInfo.catalogId);
        map.put("warehouseId", documentInfo.warehouseId);
        map.put("title", documentInfo.title);
        map.put("description", documentInfo.description);
        map.put("size", documentInfo.size);
        map.put("commentCount", documentInfo.commentCount);
        map.put("requestToken", documentInfo.requestToken);
        map.put("responseToken", documentInfo.responseToken);
        map.put("isEmbedded", documentInfo.isEmbedded);
        map.put("metadata", documentInfo.metadata);
        map.put("extra", documentInfo.extra);
        map.put("sources", documentInfo.sources);
        map.put("createdAt", documentInfo.createdAt);
        return map;
    }

    /**
     * 转换CatalogInfo为Map
     */
    private Map<String, Object> convertCatalogInfoToMap(ElasticsearchStorageStrategy.CatalogInfo catalogInfo) {
        Map<String, Object> map = new HashMap<>();
        map.put("catalogId", catalogInfo.catalogId);
        map.put("documentId", catalogInfo.documentId);
        map.put("warehouseId", catalogInfo.warehouseId);
        map.put("parentId", catalogInfo.parentId);
        map.put("name", catalogInfo.name);
        map.put("url", catalogInfo.url);
        map.put("description", catalogInfo.description);
        map.put("orderIndex", catalogInfo.orderIndex);
        map.put("isCompleted", catalogInfo.isCompleted);
        map.put("isDeleted", catalogInfo.isDeleted);
        map.put("prompt", catalogInfo.prompt);
        map.put("dependentFile", catalogInfo.dependentFile);
        map.put("gitPath", catalogInfo.gitPath);
        map.put("status", catalogInfo.status);
        map.put("likeCount", catalogInfo.likeCount);
        map.put("commentCount", catalogInfo.commentCount);
        map.put("lastUpdate", catalogInfo.lastUpdate);
        map.put("fullPath", catalogInfo.fullPath);
        map.put("level", catalogInfo.level);
        map.put("createdAt", catalogInfo.createdAt);
        return map;
    }
} 